package org.ccay.excel.exporter.internal.impl;

import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import java.util.WeakHashMap;

import javax.inject.Named;
import javax.xml.stream.XMLStreamException;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.io.Resource;

import org.ccay.core.exception.ApplicationException;
import org.ccay.core.log.ILogger;
import org.ccay.core.log.CcayLoggerFactory;
import org.ccay.core.util.StreamUtil;
import org.ccay.excel.exception.ExcelApplicationException;
import org.ccay.excel.importer.service.impl.internal.ExcelMetaParser;
import org.ccay.excel.meta.ExcelMeta;
import org.ccay.excel.meta.IExcelExportMetaManager;

/**
 * Excel元数据管理器。
 * 
 * @author chaowangbang
 * @since Mar 16, 2012
 */
@Named
public class ExcelExportMetaManager implements IExcelExportMetaManager,
		InitializingBean {

	/**
	 * ExcelMeta的缓存. 注意多线程的同步
	 */
	private Map<String, ExcelMeta> cachedExportExcelMetas = new WeakHashMap<String, ExcelMeta>();

	/**
	 * ExcelMeta解析器
	 */
	private ExcelMetaParser exelMetaParser = new ExcelMetaParser();

	// 异常编码
	private static final String GENERATETEMPLATE_EXCEPTION = "ccay.excel.00080002";

	/** 日志类 */
	private final ILogger logger = CcayLoggerFactory
			.getLogger(ExcelExportMetaManager.class);

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.ccay.excel.meta.IExcelMetaManager#getExcelMeta(java.lang
	 * .String)
	 */
	public ExcelMeta getExcelMeta(String excelType) throws ApplicationException {
		// 若缓存中存在元数据则从缓存中读取
		if (cachedExportExcelMetas.containsKey(excelType)) {
			return cachedExportExcelMetas.get(excelType);
		}

		String resPath = "config/" + excelType + ".excelExport.xml";
		InputStream in = null;
		try {
			// 获得流
			in = ExcelExportMetaManager.class.getClassLoader()
					.getResourceAsStream(resPath);
			ExcelMeta excelMeta = getExcelMetaByStream(in);
			if (excelMeta != null
					&& !cachedExportExcelMetas.containsKey(excelType)) {
				synchronized (cachedExportExcelMetas) {
					if (!cachedExportExcelMetas.containsKey(excelType)) {
						cachedExportExcelMetas.put(excelType, excelMeta);
					}
				}
			}
			return excelMeta;
		} catch (XMLStreamException e) {
			// 解析失败抛出异常
			throw new ExcelApplicationException(GENERATETEMPLATE_EXCEPTION, e);
		} finally {
			StreamUtil.closeStreams(in);
		}

	}

	/**
	 * 根据输入流解析元数据
	 * 
	 * @param is
	 * @return
	 * @throws ApplicationException
	 * @throws XMLStreamException
	 */
	private ExcelMeta getExcelMetaByStream(InputStream is)
			throws XMLStreamException, ApplicationException {
		ExcelMeta excelMeta = exelMetaParser.parse(is);
		if (excelMeta == null) {
			throw new ExcelApplicationException(GENERATETEMPLATE_EXCEPTION);
		}
		return excelMeta;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.ccay.excel.meta.IExcelMetaManager#getExcelMeta(org.
	 * springframework.core.io.Resource)
	 */
	public ExcelMeta getExcelMeta(Resource resource)
			throws ApplicationException {

		// 通过对XML文件解析，产生Excel元数据
		ExcelMeta excelMeta = null;
		InputStream in = null;
		try {
			// 根据输入流解析出Excel元数据
			in = resource.getInputStream();
			excelMeta = getExcelMetaByStream(in);
			cachedExportExcelMetas.put(excelMeta.getType(), excelMeta);
		} catch (XMLStreamException e) {
			// 解析失败抛出异常
			throw new ExcelApplicationException(GENERATETEMPLATE_EXCEPTION, e);
		} catch (IOException e) {
			// 创建流失败抛出异常
			logger.error("create InputStream failed", e);
			// 解析失败抛出异常
			throw new ExcelApplicationException(GENERATETEMPLATE_EXCEPTION, e);
		} finally {
			StreamUtil.closeStreams(in);
		}

		return excelMeta;
	}

	public void afterPropertiesSet() throws ApplicationException {

	}
}
